//
//  CityDOSDKDevice+Extend.m
//  CityDOSDK
//
//  Created by Clear Liu Lingbo on 18/10/28.
//  Copyright (c) 2018年 CityDO.com. All rights reserved.
//

#import "CityDOSDKDevice+Extend.h"

#import <ifaddrs.h>
#import <arpa/inet.h>
#import <sys/utsname.h>

#include <net/if.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <mach/mach.h>

#pragma mark - Hardware
// iPhone
NSString * const kDeviceiPhone = @"iPhone";
// iPhone 1G
NSString * const kDeviceiPhone1G = @"iPhone1,1";
// iPhone 3G
NSString * const kDeviceiPhone3G = @"iPhone1,2";
// iPhone 3GS
NSString * const kDeviceiPhone3GS = @"iPhone2";
// iPhone 4
NSString * const kDeviceiPhone4 = @"iPhone3";
// iPhone 4S
NSString * const kDeviceiPhone4S = @"iPhone4";
// iPhone 5
NSString * const kDeviceiPhone5 = @"iPhone5";
// iPhone 5S
NSString * const kDeviceiPhone5S = @"iPhone6";

// iPod
NSString * const kDeviceiPod = @"iPod";
// iPod touch 1G, N45
NSString * const kDeviceiPod1G = @"iPod1";
// iPod touch 2G, N72
NSString * const kDeviceiPod2G = @"iPod2";
// iPod touch 3G, N18
NSString * const kDeviceiPod3G = @"iPod3";
// iPod touch 4G, N80
NSString * const kDeviceiPod4G = @"iPod3";

// iPad
NSString * const kDeviceiPad = @"iPad";
// iPad 1G
NSString * const kDeviceiPad1G = @"iPad1";
// iPad 2G
NSString * const kDeviceiPad2G = @"iPad2";
// iPad 3G
NSString * const kDeviceiPad3G = @"iPad3";
// iPad 4G
NSString * const kDeviceiPad4G = @"iPad4";

/*
 Platforms

 iFPGA ->        ??

 iPhone1,1 ->    iPhone 1G, M68
 iPhone1,2 ->    iPhone 3G, N82
 iPhone2,1 ->    iPhone 3GS, N88
 iPhone3,1 ->    iPhone 4/AT&T, N89
 iPhone3,2 ->    iPhone 4/Other Carrier?, ??
 iPhone3,3 ->    iPhone 4/Verizon, TBD
 iPhone4,1 ->    (iPhone 4S/GSM), TBD
 iPhone4,2 ->    (iPhone 4S/CDMA), TBD
 iPhone4,3 ->    (iPhone 4S/???)
 iPhone5,1 ->    iPhone Next Gen, TBD
 iPhone5,1 ->    iPhone Next Gen, TBD
 iPhone5,1 ->    iPhone Next Gen, TBD

 iPod1,1   ->    iPod touch 1G, N45
 iPod2,1   ->    iPod touch 2G, N72
 iPod2,2   ->    Unknown, ??
 iPod3,1   ->    iPod touch 3G, N18
 iPod4,1   ->    iPod touch 4G, N80

 // Thanks NSForge
 iPad1,1   ->    iPad 1G, WiFi and 3G, K48
 iPad2,1   ->    iPad 2G, WiFi, K93
 iPad2,2   ->    iPad 2G, GSM 3G, K94
 iPad2,3   ->    iPad 2G, CDMA 3G, K95
 iPad3,1   ->    (iPad 3G, WiFi)
 iPad3,2   ->    (iPad 3G, GSM)
 iPad3,3   ->    (iPad 3G, CDMA)
 iPad4,1   ->    (iPad 4G, WiFi)
 iPad4,2   ->    (iPad 4G, GSM)
 iPad4,3   ->    (iPad 4G, CDMA)

 AppleTV2,1 ->   AppleTV 2, K66
 AppleTV3,1 ->   AppleTV 3, ??

 i386, x86_64 -> iPhone Simulator
 */

// 记录当前手机型号
static NSInteger currentPlatform = -1;


#pragma mark - TuSDKTSDeviceExtend
/**
 *  硬件设备扩展
 */
@implementation UIDevice(CityDOSDKDeviceExtend)

/**
 *  设备名称
 *
 *  @return 设备名称 e.g. "My iPhone"
 */
+ (NSString *)lsqName;
{
    return [[UIDevice currentDevice] name];
}

/**
 *  系统名称
 *
 *  @return 系统名称 e.g. @"iOS"
 */
+ (NSString *)lsqSystemName;
{
    return [[UIDevice currentDevice] systemName];
}

/**
 *  系统版本号
 *
 *  @return 系统版本号 e.g. @"4.0"
 */
+ (CGFloat)lsqSystemFloatVersion;
{
    return [[self lsqSystemVersion] floatValue];
}

/**
 *  系统版本号
 *
 *  @return 系统版本号 e.g. @"4.0.2"
 */
+ (NSString *)lsqSystemVersion;
{
    return [[UIDevice currentDevice] systemVersion];
}

/**
 *  硬件型号
 *
 *  @return 硬件型号 e.g. @"iPhone", @"iPod touch"
 */
+ (NSString *)lsqModel;
{
    return [[UIDevice currentDevice] model];
}

/**
 *  本地化硬件型号
 *
 *  @return 本地化硬件型号
 */
+ (NSString *)lsqLocalizedModel;
{
    return [[UIDevice currentDevice] localizedModel];
}

/**
 *  获取应用名称
 *
 *  @return 应用名称
 */
+ (NSString *)lsqAppName;
{
    NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleNameKey];
    
    // 从InfoPlist.strings 读取
    if (!appName) appName = [[NSBundle mainBundle] localizedStringForKey:@"CFBundleDisplayName" value:nil table:@"InfoPlist"];
    
    return appName;
}

/**
 *  获取应用版本
 *
 *  @return 应用版本
 */
+ (NSString *)lsqAppVersion;
{
    return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
}

/**
 *  应用编译版本
 *
 *  @return 应用编译版本
 */
+ (NSString *)lsqAppBuild;
{
    return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
}

/**
 *  应用 Bundle Identifier
 *
 *  @return 应用 Bundle Identifier
 */
+ (NSString *)lsqAppIdentifier;
{
    return [[NSBundle mainBundle] bundleIdentifier];
}

/**
 *  开启应用设置页面
 */
+ (void)lsqOpenAppSettings  NS_AVAILABLE_IOS(8_0);
{
    if ([self lsqSystemFloatVersion] < 8.0) return;
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString: UIApplicationOpenSettingsURLString]];
}

/**
 *  获取WIFI IP地址
 *
 *  @return WIFI IP地址
 */
+ (NSString *)lsqGetWifiIpAddress;
{
    BOOL success;
    struct ifaddrs * addrs;
    const struct ifaddrs * cursor;

    success = getifaddrs(&addrs) == 0;
    if (success) {
        cursor = addrs;
        while (cursor != NULL) {
            // the second test keeps from picking up the loopback address
            if (cursor->ifa_addr->sa_family == AF_INET && (cursor->ifa_flags & IFF_LOOPBACK) == 0)
            {
                NSString *name = [NSString stringWithUTF8String:cursor->ifa_name];
                if ([name isEqualToString:@"en0"])  // Wi-Fi adapter
                return [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)cursor->ifa_addr)->sin_addr)];
            }
            cursor = cursor->ifa_next;
        }
        freeifaddrs(addrs);
    }
    return nil;
}

/**
 *  获取文件大小 BYTE
 *
 *  @param filePath 文件路径
 *
 *  @return 文件大小 BYTE
 */
+ (long long)lsqFileSizeAtPath:(NSString *)filePath;
{
    struct stat st;
    if(lstat([filePath cStringUsingEncoding:NSUTF8StringEncoding], &st) == 0){
        return st.st_size;
    }
    return 0;
}

/**
 *  打印内存使用情况
 *
 *  @param tag 标签
 */
+ (void)lsqLogMemory:(NSString *)tag;
{
//    NSLog(@"%@ : {space: %f, user: %f}", tag, [self lsqSpaceMemory], [self lsqUsedMemory]);
}

/**
 硬件性能
 
 iPhone 6   - platform: iPhone7,2, performance: 6
 iPhone 6P  - platform: iPhone7,1, performance: 6
 iPhone 6S  - platform: iPhone8,1, performance: 7
 iPhone 6SP - platform: iPhone8,2, performance: 7
 iPhone SE - platform: iPhone8,4, performance: 7
 iPhone 7   - platform: iPhone9,1, performance: 8
 iPhone 7P  - platform: iPhone9,2, performance: 8

 @return
 */
+ (NSUInteger)lsqPerformance;
{
//    NSString *platform = [[self currentDevice]lsqPlatform];
//
//    if (!platform) return 2;
//
//    NSArray *result = [platform lsqSubstringByRegular:@"([a-zA-Z]+)([0-9]+),([0-9]+)"];
//
//    if (!result || result.count != 4) return 2;
//
//    // lsqLDebug(@"performance: %@ | %@ | %@", result[1], result[2], result[3]);
//
//    NSInteger per = [result[2] intValue];
//
//    if ([result[1] isEqualToString:@"iPhone"]) {
//        per --;
//    }else if ([result[1] isEqualToString:@"iPad"]){
//        if (per > 3 || (per == 3 && [result[3] intValue] > 3)) {
//            per ++;
//        }
//    }else if ([result[1] isEqualToString:@"iPod"]){
//        per -= 2;
//    }
//    return MAX(per, 0);
    return  2;
}


/**
 获取手机型号

 @return TuSDKDevicePlatform 手机型号枚举
 */
+ (TuSDKDevicePlatform)lsqDevicePlatform;
{
    struct utsname systemInfo;
    uname(&systemInfo);
    NSString *platform = [NSString stringWithCString: systemInfo.machine encoding:NSASCIIStringEncoding];

    if (currentPlatform != -1) {
        return currentPlatform;
    }

    if([platform isEqualToString:@"iPhone1,1"]){
        currentPlatform = TuSDKDevicePlatform_iPhone2G;
        
    }else if([platform isEqualToString:@"iPhone1,2"]){
        currentPlatform = TuSDKDevicePlatform_iPhone3G;
        
    }else if([platform isEqualToString:@"iPhone2,1"]){
        currentPlatform = TuSDKDevicePlatform_iPhone3GS;
        
    }else if([platform isEqualToString:@"iPhone3,1"]){
        currentPlatform = TuSDKDevicePlatform_iPhone4;
        
    }else if([platform isEqualToString:@"iPhone3,2"]){
        currentPlatform = TuSDKDevicePlatform_iPhone4;
        
    }else if([platform isEqualToString:@"iPhone3,3"]){
        currentPlatform = TuSDKDevicePlatform_iPhone4;
        
    }else if([platform isEqualToString:@"iPhone4,1"]){
        currentPlatform = TuSDKDevicePlatform_iPhone4s;
        
    }else if([platform isEqualToString:@"iPhone5,1"]){
        currentPlatform = TuSDKDevicePlatform_iPhone5;
        
    }else if([platform isEqualToString:@"iPhone5,2"]){
        currentPlatform = TuSDKDevicePlatform_iPhone5;
        
    }else if([platform isEqualToString:@"iPhone5,3"]){
        currentPlatform = TuSDKDevicePlatform_iPhone5c;
        
    }else if([platform isEqualToString:@"iPhone5,4"]){
        currentPlatform = TuSDKDevicePlatform_iPhone5c;
        
    }else  if([platform isEqualToString:@"iPhone6,1"]){
        currentPlatform = TuSDKDevicePlatform_iPhone5s;
        
    }else if([platform isEqualToString:@"iPhone6,2"]){
        currentPlatform = TuSDKDevicePlatform_iPhone5s;
        
    }else if([platform isEqualToString:@"iPhone7,1"]){
        currentPlatform = TuSDKDevicePlatform_iPhone6p;
        
    }else if([platform isEqualToString:@"iPhone7,2"]){
        currentPlatform = TuSDKDevicePlatform_iPhone6;
        
    }else if([platform isEqualToString:@"iPhone8,1"]){
        currentPlatform = TuSDKDevicePlatform_iPhone6s;
        
    }else if([platform isEqualToString:@"iPhone8,2"]){
        currentPlatform = TuSDKDevicePlatform_iPhone6sp;
        
    }else if([platform isEqualToString:@"iPhone8,4"]){
        currentPlatform = TuSDKDevicePlatform_iPhoneSE;
        
    }else if([platform isEqualToString:@"iPhone9,1"]){
        currentPlatform = TuSDKDevicePlatform_iPhone7;
        
    }else if([platform isEqualToString:@"iPhone9,2"]){
        currentPlatform = TuSDKDevicePlatform_iPhone7p;
        
    }else if([platform isEqualToString:@"iPhone10,1"]){
        currentPlatform = TuSDKDevicePlatform_iPhone8;
        
    }else if([platform isEqualToString:@"iPhone10,4"]){
        currentPlatform = TuSDKDevicePlatform_iPhone8;
        
    }else if([platform isEqualToString:@"iPhone10,2"]){
        currentPlatform = TuSDKDevicePlatform_iPhone8p;
        
    }else if([platform isEqualToString:@"iPhone10,5"]){
        currentPlatform = TuSDKDevicePlatform_iPhone8p;
        
    }else if([platform isEqualToString:@"iPhone10,3"]){
        currentPlatform = TuSDKDevicePlatform_iPhoneX;
        
    }else if([platform isEqualToString:@"iPhone10,6"]){
        currentPlatform = TuSDKDevicePlatform_iPhoneX;
        
    }else if([platform isEqualToString:@"iPod1,1"]){
        currentPlatform = TuSDKDevicePlatform_iPod1G;
        
    }else if([platform isEqualToString:@"iPod2,1"]){
        currentPlatform = TuSDKDevicePlatform_iPod2G;
        
    }else if([platform isEqualToString:@"iPod3,1"]){
        currentPlatform = TuSDKDevicePlatform_iPod3G;
        
    }else if([platform isEqualToString:@"iPod4,1"]){
        currentPlatform = TuSDKDevicePlatform_iPod4G;
        
    }else if([platform isEqualToString:@"iPod5,1"]){
        currentPlatform = TuSDKDevicePlatform_iPod5G;
        
    }else if([platform isEqualToString:@"i386"]){
        currentPlatform = TuSDKDevicePlatform_Simulator;

    }else if([platform isEqualToString:@"x86_64"]){
        currentPlatform = TuSDKDevicePlatform_Simulator;

    }else{
        currentPlatform = TuSDKDevicePlatform_other;
    }

    return currentPlatform;
    
}


/**
 判断当前手机是否为iPhoneX
 */
+ (BOOL)lsqIsDeviceiPhoneX;
{
    // 真机运行
    if ([self lsqDevicePlatform] == TuSDKDevicePlatform_iPhoneX){
        return YES;
    }
    
    // 模拟器运行
    CGSize size = CGSizeMake(375, 812);
    if ([self lsqDevicePlatform] == TuSDKDevicePlatform_Simulator  && CGSizeEqualToSize(size, [UIScreen mainScreen].bounds.size)){
        return YES;
    }
    
    return NO;
}

/**
 *  获取当前应用可用内存(单位：MB）
 *
 *  @return 当前应用可用内存(单位：MB）
 */
+ (double)lsqSpaceMemory;
{
    vm_statistics_data_t vmStats;
    mach_msg_type_number_t infoCount = HOST_VM_INFO_COUNT;
    kern_return_t kernReturn = host_statistics(mach_host_self(),
                                               HOST_VM_INFO,
                                               (host_info_t)&vmStats,
                                               &infoCount);

    if (kernReturn != KERN_SUCCESS) {
        return NSNotFound;
    }

    return ((vm_page_size *vmStats.free_count) / 1024.0) / 1024.0;
}

/**
 *  获取当前应用所占用的内存（单位：MB）
 *
 *  @return 当前应用所占用的内存（单位：MB）
 */
+ (double)lsqUsedMemory;
{
    task_basic_info_data_t taskInfo;
    mach_msg_type_number_t infoCount = TASK_BASIC_INFO_COUNT;
    kern_return_t kernReturn = task_info(mach_task_self(),
                                         TASK_BASIC_INFO,
                                         (task_info_t)&taskInfo,
                                         &infoCount);

    if (kernReturn != KERN_SUCCESS
        ) {
        return NSNotFound;
    }

    return taskInfo.resident_size / 1024.0 / 1024.0;
}

/**
 *  Universally Unique Identifier 通用唯一识别码
 *
 *  @return 通用唯一识别码
 */
+ (NSString*)lsqUuid;
{
    CFUUIDRef puuid = CFUUIDCreate( nil );
    CFStringRef uuidString = CFUUIDCreateString( nil, puuid );
    NSString * result = (NSString *)CFBridgingRelease(CFStringCreateCopy( NULL, uuidString));
    CFRelease(puuid);
    CFRelease(uuidString);
    return result;
}

#pragma mark sysctlbyname utils
/**
 *  获取系统信息
 *
 *  @param typeSpecifier 信息标识
 *
 *  @return 系统信息
 */
- (NSString *)lsqGetSysInfoByName:(char *)typeSpecifier;
{
    size_t size;
    sysctlbyname(typeSpecifier, NULL, &size, NULL, 0);

    char *answer = malloc(size);
    sysctlbyname(typeSpecifier, answer, &size, NULL, 0);

    NSString *results = [NSString stringWithCString:answer encoding: NSUTF8StringEncoding];

    free(answer);
    return results;
}

/**
 *  硬件名称
 *
 *  @return 硬件名称
 */
- (NSString *)lsqPlatform;
{
    return [self lsqGetSysInfoByName:"hw.machine"];
}

/**
 *  是否为指定设备
 *
 *  @param device 设备名称
 *
 *  @return 是否为指定设备
 */
- (BOOL)lsqIsDevice:(NSString *)device;
{
    NSString *cPlat = [self lsqPlatform];
    if (!device || !cPlat) false;

    return [cPlat hasPrefix:device];
}

/**
 *  硬件类型
 *
 *  @return 硬件类型
 */
- (NSString *)lsqHwmodel;
{
    return [self lsqGetSysInfoByName:"hw.model"];
}

#pragma mark sysctl utils
/**
 *  获取系统信息
 *
 *  @param typeSpecifier 信息标识
 *
 *  @return 系统信息
 */
- (NSUInteger)lsqGetSysInfo: (uint) typeSpecifier;
{
    size_t size = sizeof(int);
    int results;
    int mib[2] = {CTL_HW, typeSpecifier};
    sysctl(mib, 2, &results, &size, NULL, 0);
    return (NSUInteger) results;
}

/**
 *  CPU频率
 *
 *  @return CPU频率
 */
- (NSUInteger)lsqCpuFrequency;
{
    return [self lsqGetSysInfo:HW_CPU_FREQ];
}

/**
 *  系统总线频率
 *
 *  @return 系统总线频率
 */
- (NSUInteger)lsqBusFrequency;
{
    return [self lsqGetSysInfo:HW_BUS_FREQ];
}

/**
 *  CPU核心数
 *
 *  @return CPU核心数
 */
- (NSUInteger)lsqCpuCount;
{
    return [self lsqGetSysInfo:HW_NCPU];
}

/**
 *  合计内存
 *
 *  @return 合计内存
 */
- (NSUInteger)lsqTotalMemory;
{
    return [self lsqGetSysInfo:HW_PHYSMEM];
}

/**
 *  已使用内存
 *
 *  @return 已使用内存
 */
- (NSUInteger)lsqUserMemory;
{
    return [self lsqGetSysInfo:HW_USERMEM];
}

- (NSUInteger)lsqSapceMemory;
{
    return [self lsqTotalMemory] - [self lsqUserMemory];
}

/**
 *  空闲内存
 *
 *  @return 空闲内存
 */
- (NSUInteger)lsqMaxSocketBufferSize;
{
    return [self lsqGetSysInfo:KIPC_MAXSOCKBUF];
}

/**
 *  总存储空间
 *
 *  @return 总存储空间
 */
- (NSNumber *)lsqTotalDiskSpace;
{
    NSDictionary *fattributes = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil];
    return [fattributes objectForKey:NSFileSystemSize];
}

/**
 *  可使用存储空间
 *
 *  @return 可使用存储空间
 */
- (NSNumber *)lsqFreeDiskSpace;
{
    NSDictionary *fattributes = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil];
    return [fattributes objectForKey:NSFileSystemFreeSize];
}



#pragma mark MAC addy
// Return the local MAC addy
// Courtesy of FreeBSD hackers email list
// Accidentally munged during previous update. Fixed thanks to mlamb.
/**
 *  网络Mac地址
 *
 *  @return 网络Mac地址
 */
- (NSString *)lsqMacaddress;
{
    int                 mib[6];
    size_t              len;
    char                *buf;
    unsigned char       *ptr;
    struct if_msghdr    *ifm;
    struct sockaddr_dl  *sdl;

    mib[0] = CTL_NET;
    mib[1] = AF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_LINK;
    mib[4] = NET_RT_IFLIST;

    if ((mib[5] = if_nametoindex("en0")) == 0) {
        printf("Error: if_nametoindex error\n");
        return NULL;
    }

    if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 1\n");
        return NULL;
    }

    if ((buf = malloc(len)) == NULL) {
        printf("Error: Memory allocation error\n");
        return NULL;
    }

    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 2\n");
        free(buf); // Thanks, Remy "Psy" Demerest
        return NULL;
    }

    ifm = (struct if_msghdr *)buf;
    sdl = (struct sockaddr_dl *)(ifm + 1);
    ptr = (unsigned char *)LLADDR(sdl);
    NSString *outstring = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];

    free(buf);
    return outstring;
}

/**
 *  根据设备方向获取旋转角度
 *
 *  @param orient 设备旋转方向
 *
 *  @return 旋转角度
 */
+ (CGFloat)lsqGetRotationByOrient:(UIDeviceOrientation)orient;
{
    switch (orient) {
        case UIDeviceOrientationPortraitUpsideDown:
            return M_PI;
        case UIDeviceOrientationLandscapeLeft:
            return M_PI_2;
        case UIDeviceOrientationLandscapeRight:
            return -M_PI_2;
        case UIDeviceOrientationPortrait:
        default:
            return 0;
    }
}

/**
 * 获取设备当前语言
 */
+(NSString *)lsqCurrentLanguage;
{
    NSArray *languages = [NSLocale preferredLanguages];
    NSString *currentLanguage = [languages objectAtIndex:0];
   
    return currentLanguage;
}

/**
 * 判断当前是否为中文环境
 */
+(Boolean)lsqCNLanguage;
{
     return [[self lsqCurrentLanguage] hasPrefix:@"zh-"];
}

@end
